//
//  UIViewController+DataBind.m
//  DataBind
//
//  Created by Super on 2019/12/16.
//  Copyright © 2019 Super. All rights reserved.
//

#import "UIViewController+DataBind.h"
#import "UIView+DataBind.h"
#import <objc/runtime.h>

static const char *kDataBindRegisterListPropertyKey = "kDataBindRegisterListPropertyKey";

@implementation UIViewController (DataBind)
//关联属性  绑定数据的列表
- (NSMutableArray *)dataBindRegisterList {
    return objc_getAssociatedObject(self, kDataBindRegisterListPropertyKey);
}
 
- (void)setDataBindRegisterList:(NSMutableArray *)dataBindRegisterList {
    objc_setAssociatedObject(self,kDataBindRegisterListPropertyKey, dataBindRegisterList, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

/*---------------------数据绑定方法---------------------*/
- (void)bindModel:(DataBindModel *)model modelKey:(NSString *)modelKey viewInfo:(NSDictionary *)viewInfo block:(dispatch_block_t)block {
    [self bindModel:model modelKey:modelKey viewInfo:viewInfo bindType:BindViewAndModel block:block];
}

- (void)bindModel:(DataBindModel *)model modelKey:(NSString *)modelKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    [self bindModel:model modelKey:modelKey propertyKey:nil viewInfo:viewInfo bindType:bindType block:block];
}

- (void)bindPropertyWithKey:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo block:(dispatch_block_t)block {
    [self bindPropertyWithKey:propertyKey viewInfo:viewInfo bindType:BindViewAndModel block:block];
}

- (void)bindPropertyWithKey:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    [self bindModel:nil modelKey:nil propertyKey:propertyKey viewInfo:viewInfo bindType:bindType block:block];
}

- (void)bindModel:(DataBindModel *)model modelKey:(NSString *)modelKey propertyKey:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    //绑定的信息不全
    if (propertyKey == nil && (model == nil || modelKey == nil)) {
        NSLog(@"请检查绑定参数是否正确");
        return;
    }

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        UIView *bindView = [viewInfo objectForKey:@"bindUI"];  //当前被绑定的视图
        UIView *bindProp = [viewInfo objectForKey:@"UIBindProp"];  //当前被绑定的视图属性
        
        NSInteger bindIndex = -1;
        for (int i=0; i < self.dataBindRegisterList.count; i++) {
            NSDictionary *dict = self.dataBindRegisterList[i];
            UIView *bindUI = [dict objectForKey:@"bindUI"];  //被绑定的视图
            NSString *uiBindProp = [dict objectForKey:@"UIBindProp"];  //被绑定的视图属性
            //判断该视图是否已被绑定
            if (bindUI == bindView && [bindProp isEqual:uiBindProp]) {
                //该视图已被绑定  更新绑定信息
                bindIndex = i;
                break;
            }
        }
        
        if (bindIndex < 0) {
            //未被绑定  执行绑定逻辑
            NSDictionary *bindInfo = [self bindWithModel:model modelKey:modelKey propertyKey:propertyKey viewInfo:viewInfo bindType:bindType block:block];
            [self.dataBindRegisterList addObject:bindInfo];

        } else {
            //已被绑定  更新绑定数据
            NSDictionary *oldBindInfo = self.dataBindRegisterList[bindIndex];
            [self unBindWithOldBindInfo:oldBindInfo];
            [self.dataBindRegisterList removeObjectAtIndex:bindIndex];
            NSDictionary *bindInfo = [self bindWithModel:model modelKey:modelKey propertyKey:propertyKey viewInfo:viewInfo bindType:bindType block:block];
            [self.dataBindRegisterList addObject:bindInfo];
        }
        dispatch_semaphore_signal(semaphore);
    });
}

//执行绑定
- (NSDictionary *)bindWithModel:(DataBindModel *)model modelKey:(NSString *)modelKey propertyKey:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    if (propertyKey == nil) {
        return [self bindModelWithBindType:bindType model:model modelKey:modelKey viewInfo:viewInfo block:block];
    } else {
        return [self bindPropertyWithBindType:bindType propertyKey:propertyKey viewInfo:viewInfo block:block];
    }
}

//执行解绑
- (void)unBindWithOldBindInfo:(NSDictionary *)oldBindInfo {
    NSString *isProperty = [oldBindInfo objectForKey:@"isProperty"];
    if (isProperty.intValue) {
        [self unBindPropertyWithOldBindInfo:oldBindInfo];
    } else {
        [self unBindModelWithOldBindInfo:oldBindInfo];
    }
}

//执行Model绑定 获取绑定信息
- (NSDictionary *)bindModelWithBindType:(BindType)bindType model:(DataBindModel *)model modelKey:(NSString *)modelKey viewInfo:(NSDictionary *)viewInfo block:(dispatch_block_t)block {
    UIView *bindView = [viewInfo objectForKey:@"bindUI"];
    NSString *bindProp = [viewInfo objectForKey:@"UIBindProp"];
    switch (bindType) {
        case BindViewAndModel:
            [self initViewData:model dataSourceKey:modelKey receiverView:bindView receiverKey:bindProp];
            [model bindKey:modelKey observer:self];
            [bindView bindKey:bindProp observer:self];
            break;
        case BindViewToModel:
            [bindView bindKey:bindProp observer:self];
            break;
        case BindModelToView:
            [self initViewData:model dataSourceKey:modelKey receiverView:bindView receiverKey:bindProp];
            [model bindKey:modelKey observer:self];
            break;
        default:
            break;
    }
    return [self getBindInfoDictWithModel:model modelKey:modelKey viewInfo:viewInfo bindType:bindType block:block];
}

//执行Model解绑
- (void)unBindModelWithOldBindInfo:(NSDictionary *)oldBindInfo {
    DataBindModel *oldModel = [oldBindInfo objectForKey:@"model"];
    NSString *oldModelKey = [oldBindInfo objectForKey:@"modelKey"];
    UIView *bindView = [oldBindInfo objectForKey:@"bindUI"];
    NSString *bindProp = [oldBindInfo objectForKey:@"UIBindProp"];
    NSNumber *bindType = [oldBindInfo objectForKey:@"bindType"];
    switch (bindType.intValue) {
        case BindViewAndModel:
            [oldModel unbindKey:oldModelKey observer:self];
            [bindView unbindKey:bindProp observer:self];
            break;
        case BindViewToModel:
            [bindView unbindKey:bindProp observer:self];
            break;
        case BindModelToView:
            [oldModel unbindKey:oldModelKey observer:self];
            break;
        default:
            break;
    }
}

//执行属性绑定 获取绑定信息
- (NSDictionary *)bindPropertyWithBindType:(BindType)bindType propertyKey:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo block:(dispatch_block_t)block {
    UIView *bindView = [viewInfo objectForKey:@"bindUI"];
    NSString *bindProp = [viewInfo objectForKey:@"UIBindProp"];
    switch (bindType) {
        case BindViewAndModel:
            [self initViewData:self dataSourceKey:propertyKey receiverView:bindView receiverKey:bindProp];
            [self bindKey:propertyKey];
            [bindView bindKey:bindProp observer:self];
            break;
        case BindViewToModel:
            [bindView bindKey:bindProp observer:self];
            break;
        case BindModelToView:
            [self initViewData:self dataSourceKey:propertyKey receiverView:bindView receiverKey:bindProp];
            [self bindKey:propertyKey];
            break;
        default:
            break;
    }
    return [self getBindInfoDictWithProperty:propertyKey viewInfo:viewInfo bindType:bindType block:block];
}

//执行属性解绑
- (void)unBindPropertyWithOldBindInfo:(NSDictionary *)oldBindInfo {
    NSString *propertyKey = [oldBindInfo objectForKey:@"propertyKey"];
    UIView *bindView = [oldBindInfo objectForKey:@"bindUI"];
    NSString *bindProp = [oldBindInfo objectForKey:@"UIBindProp"];
    NSNumber *bindType = [oldBindInfo objectForKey:@"bindType"];
    switch (bindType.intValue) {
        case BindViewAndModel:
            [self unbindKey:propertyKey];
            [bindView unbindKey:bindProp observer:self];
            break;
        case BindViewToModel:
            [bindView unbindKey:bindProp observer:self];
            break;
        case BindModelToView:
            [self unbindKey:propertyKey];
            break;
        default:
            break;
    }
}

//初始化视图的数据（从model或者属性同步）
- (void)initViewData:(id)dataSourceObj dataSourceKey:(NSString *)dataSourceKey receiverView:(UIView *)receiverView receiverKey:(NSString *)receiverKey{
    id value = [dataSourceObj valueForKey:dataSourceKey];
    if (value != NULL) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [receiverView updateChange:receiverKey value:value];
        });
    }
}

- (NSDictionary *)getBindInfoDictWithModel:(DataBindModel *)model modelKey:(NSString *)modelKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    NSMutableDictionary *dict = [self getBindInfoDictBaseWithViewInfo:viewInfo bindType:bindType block:block];
    [dict setObject:model forKey:@"model"];  //绑定的Model
    [dict setObject:modelKey forKey:@"modelKey"]; //绑定Model的Key
    return [NSDictionary dictionaryWithDictionary:dict];
}

- (NSDictionary *)getBindInfoDictWithProperty:(NSString *)propertyKey viewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    NSMutableDictionary *dict = [self getBindInfoDictBaseWithViewInfo:viewInfo bindType:bindType block:block];
    [dict setObject:@"1" forKey:@"isProperty"]; //是否是属性绑定的标识符
    [dict setObject:propertyKey forKey:@"propertyKey"];  //绑定属性的Key
    return [NSDictionary dictionaryWithDictionary:dict];
}

- (NSMutableDictionary *)getBindInfoDictBaseWithViewInfo:(NSDictionary *)viewInfo bindType:(BindType)bindType block:(dispatch_block_t)block {
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:viewInfo];
    [dict setObject:[NSNumber numberWithInt:bindType] forKey:@"bindType"];
    [dict setObject:block forKey:@"dataChangeBlock"]; //数据回调block
    [dict setObject:self forKey:@"observer"];  //观察者对象
    return dict;
}

- (void)bindKey:(NSString *)key {
    [self addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}

- (void)unbindKey:(NSString *)key {
    [self removeObserver:self forKeyPath:key];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    
}

@end
